<?php
/**
 * This is a class that is used to parse a string and format it
 * for BBCode. This class implements the use of a unique
 * identifier, for the purpose of saving resources, post-database.
 * Based on code from Matt Carroll <admin@develogix.com>
 *
 * @author          Martin Pernica <martin.developer@centrum.cz>
 */
class bbcode
{
    private $str = "";
    private $action = null;

    private $added = array();
    
    private $imgLimit = 10;

    public function __construct()
    {

    }

    /**
     * @param  str    string to be parsed
     * @param  action 'pre' or 'post' database, null for standard parse
     *
     * @return parsed string
     */
    public function parse($str, $action)
    {
        $this->str = $str;
        $this->action = $action;
        
        $this->bbQuote();
        $this->_bbCode();
        $this->bbHtml();
        $this->bbImg();
        $this->bbList();
        $this->bbMail();
        $this->bbPhp();
        $this->bbSimple();
        $this->bbUrl();
		$this->bbOrderedList();
		$this->bbColor();
        $this->bbBr();
        
        return $this->str;
    }

    /**
     * @param var function name to disallow
     */
    public function disallow($var)
    {
        $this->{$var} = false;
    }

    /**
     * @param var function name to allow
     */
    public function allow($var)
    {
        $this->{$var} = true;
    }

    /**
     * sets image limit
     * @param limit amount of images to be parsed (-1 for unlimited)
     */
    public function imgLimit($limit)
    {
        $this->imgLimit = $limit;
    }

    private function bbHtml()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[html\](.*?)\[/html\]#si', '#\[html\](.*?)\[/html\]#si');
                $replace = array('[html]$1[/html]',
                    '[html]$1[/html]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('#\[html\](.*?)\[/html\]#si',
                    '#\[html\](.*?)\[/html\]#si');
                $replace = array('<pre class="jush">$1</pre>');
                $this->str = preg_replace($match, $replace, $this->str);
            }
    }

    private function bbPhp()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[php\](.*?)\[/php\]#si', '#\[php\](.*?)\[/php\]#si');
                $replace = array('[php]$1[/php]', '[php]$1[/php]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('#\[php\](.*?)\[/php\]#si',
                    '#\[php\](.*?)\[/php\]#si');
                $replace = array('<pre class="jush-php">$1</pre>');
                $this->str = preg_replace($match, $replace, $this->str);
            }
    }

    /**
     * parses string for [list], [*]
     */
    private function bbList()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[list\](.*?)\[/list\]#si', '#\[\*\](.*?)\[/\*\]#si');
                $replace = array('[list]$1[/list]', '[*]$1[/*]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('[list]', '[/list]', '[*]', '[/*]');
                $replace = array('<ul>', '</ul>', '<li>', '</li>');
                $this->str = str_replace($match, $replace, $this->str);
            }
    }
    
    /**
     * parses string for [olist], [*]
     */
    private function bbOrderedList()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[olist\](.*?)\[/olist\]#si', '#\[\*\](.*?)\[/\*\]#si');
                $replace = array('[olist]$1[/olist]', '[*]$1[/*]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('[olist]', '[/olist]', '[*]', '[/*]');
                $replace = array('<ol>', '</ol>', '<li>', '</li>');
                $this->str = str_replace($match, $replace, $this->str);
            }
    }

    /**
     * parses string for [b], [i], [u], [s], [em], [sup], and [sub]
     */
    private function bbSimple()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[b\](.*?)\[/b\]#si', '#\[i\](.*?)\[/i\]#si', '#\[u\](.*?)\[/u\]#si',
                    '#\[s\](.*?)\[/s\]#si', '#\[em\](.*?)\[/em\]#si', '#\[sup\](.*?)\[/sup\]#si', '#\[sub\](.*?)\[/sub\]#si');
                $replace = array('[b]$1[/b]', '[i]$1[/i]', '[u]$1[/u]', '[s]$1[/s]', '[em]$1[/em]', '[sup]$1[/sup]', '[sub]$1[/sub]');
                foreach ($this->added as $arr) {
                    $match[] = '#\[' . $arr[0] . '\](.*?)\[/' . $arr[0] . '\]#si';
                    $replace[] = '[' . $arr[0] . ']$1[/' . $arr[0] . ']';
                }
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('[b]', '[/b]', '[i]', '[/i]', '[u]', '[/u]', '[s]', '[/s]', '[em]', '[/em]', '[sup]', '[/sup]', '[sub]', '[/sub]');
                $replace = array('<strong>', '</strong>', '<em>', '</em>',
                    '<span style="text-decoration: underline;">', '</span>', '<del>', '</del>',
                    '<em>', '</em>', '<sup>', '</sup>', '<sub>', '</sub>');
                foreach ($this->added as $arr) {
                    $match[] = '[' . $arr[0] . ']';
                    $replace[] = $arr[1];
                    $match[] = '[/' . $arr[0] . ']';
                    $replace[] = $arr[2];
                }
                $this->str = str_replace($match, $replace, $this->str);
            }
    }
    
    /**
     * parses string for [color=*] and [color]
     */
    private function bbColor()
    {
            if ($this->action == 'pre') {
                $match = array('#\[color=(.*?)\](.*?)\[/color\]#si', '#\[color\](.*?)\[/color\]#si');
                $replace = array('[color=$1]$2[/color]',
                    '[color]$1[/color]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action == 'post') {
                $match = array('#\[color=(.*?)\](.*?)\[/color\]#si', '#\[color\](.*?)\[/color\]#si');
                $replace = array('<span style="color: $1">$2</span>',
                    '<span>$1</span>');
                $this->str = preg_replace($match, $replace, $this->str);
            }
    }

    /**
     * parses string for [quote=*] and [quote]
     */
    private function bbQuote()
    {
            if ($this->action == 'pre') {
                $match = array('#\[quote=(.*?)\](.*?)\[/quote\]#si', '#\[quote\](.*?)\[/quote\]#si');
                $replace = array('[quote=$1]$2[/quote]',
                    '[quote]$1[/quote]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action == 'post') {
                $match = array('#\[quote=(.*?)\](.*?)\[/quote\]#si', '#\[quote\](.*?)\[/quote\]#si');
                $replace = array('<blockquote>Reaguje na <strong><em>$1</em></strong><br />$2</blockquote>',
                    '<blockquote><p><strong>Reakce</strong></p><p>$1</p></blockquote>');
                $this->str = preg_replace($match, $replace, $this->str);
            }
    }

    /**
     * parses string for [code] and [code]
     */
    private function _bbCode()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[code\](.*?)\[/code\]#si', '#\[code\](.*?)\[/code\]#si');
                $replace = array('[code]$1[/code]','[code]$1[/code]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('#\[code\](.*?)\[/code\]#si');
                $replace = array('<code><p class="code">$1</p></code>');
                $this->str = preg_replace($match, $replace, $this->str);
            }
    }


    /**
     * parses string for [mail=*] and [mail]
     */
    private function bbMail()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#\[mail=([a-z0-9\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+)\](.*?)\[/mail\]#si',
                    '#\[mail\]([a-z0-9\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+)\[/mail\]#si');
                $replace = array('[mail=$1]$2[/mail]',
                    '[mail=$1]$1[/mail]');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = '#\[mail=([a-z0-9\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+)\](.*?)\[/quote\]#si';
                $replace = '<a href="mailto:$1">$2</a>';
                $this->str = preg_replace($match, $replace, $this->str);
            }
    }

    /**
     * parses string for [url=*], [url], and unformatted URLs
     */
    private function bbUrl()
    {
            if ($this->action === 'pre' or $this->action === null) {
                $match = array('#(?<!(\]|=|\/))((http|https|ftp|irc|telnet|gopher|afs)\:\/\/|www\.)(.+?)( |\n|\r|\t|\[|$)#si',
                    '#\[url\]([a-z0-9]+?://){1}([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^ \"\n\r\t<]*)?)\[/url\]#is',
                    '#\[url\]((www|ftp)\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^ \"\n\r\t<]*?)?)\[/url\]#si',
                    '#\[url=([a-z0-9]+://)([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^ \"\n\r\t<]*?)?)\](.*?)\[/url\]#si',
                    '#\[url=(([\w\-]+\.)*?[\w]+(:[0-9]+)?(/[^ \"\n\r\t<]*)?)\](.*?)\[/url\]#si');
                $replace = array('[url]$1$2$4[/url]$5',
                    '[url]$1$2[/url]', '[url]http://$1[/url]', '[url=$1$2]$6[/url]', '[url=http://$1]$5[/url');
                $this->str = preg_replace($match, $replace, $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = array('#\[url\](.*?)\[/url\]#si',
                    '#\[url=(.*?)\](.*?)\[/url\]#si');
                $replace = array('<a href="$1">$1</a>', '<a href="$1">$2</a>');
                $this->str = preg_replace($match, $replace, $this->str);

                if (!function_exists('bbUrl2')) {
                    function bbUrl2($matches)
                    {
                        return '<a href="' . str_replace('&', '&amp;', str_replace('&amp;', '&', $matches[1])) .
                            '">';
                    }
                }
                $this->str = preg_replace_callback('#<a href="(.*?)">#si', 'bbUrl2'
                    /*array($this, bbUrl2)*/, $this->str);
            }
    }

    /**
     * fixes problem in bbUrl that occurs when trying to run a callback
     * @param $matches matches from preg_replace_callback within bbUrl
     */

    private function bbUrl2($matches)
    {
        return '<a href="' . str_replace('&', '&amp;', str_replace('&amp;', '&', $matches[1])) .
            '">';
    }

    /**
     * parses string for [img], limited to $this->imgLimit amount of times
     */
    private function bbImg()
    {
            if ($this->action === 'pre') {
                $match = '#\[img\](.*?)\[\/img\]#si';
                $replace = '[img]$1[/img]';
                $this->str = preg_replace($match, $replace, $this->str/*, $this->imgLimit*/);
            }

            if ($this->action === 'post' or $this->action === null) {
                $match = "/\[img\](.*?)\[\/img\]/is";
                $replace = '<img src="$1" alt="$1" title="Image" />';
                $this->str = preg_replace($match, $replace, $this->str/*, $this->imgLimit*/);
            }
    }
    
    private function bbBr(){
        if ($this->action === 'pre') {
                $this->str = str_replace(array("\n\r", "\n"), array('[br]', '[br]'), $this->str);
            }

            if ($this->action === 'post' or $this->action === null) {
                $this->str = str_replace('[br]', '<br />', $this->str);
            }
    }
}
?>